/*
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.inspur.edp.bff.designtime.generator.core.extendaction.method;

import com.inspur.edp.bef.component.detailcmpentity.vm.VMComponent;
import com.inspur.edp.bef.component.detailcmpentity.vm.VMMethod;
import com.inspur.edp.bff.designtime.generator.core.VmCoreGenContext;
import com.inspur.edp.bff.spi.action.changemapping.ChangeMappingAction;
import com.inspur.edp.bff.spi.action.changemapping.ChangeReversalMappingAction;
import com.inspur.edp.bff.spi.action.changemapping.DefaultChangeMapAction;
import com.inspur.edp.bff.spi.action.changemapping.DefaultChangeReversalAction;
import com.inspur.edp.bff.spi.action.datamapping.DataMappingAction;
import com.inspur.edp.bff.spi.action.datamapping.DataReversalMappingAction;
import com.inspur.edp.bff.spi.action.datamapping.DefaultDataMappingAction;
import com.inspur.edp.bff.spi.action.datamapping.DefaultDataReversalAction;
import com.inspur.edp.bff.spi.action.delete.AbstractDeleteAction;
import com.inspur.edp.bff.spi.action.delete.AfterDeleteAction;
import com.inspur.edp.bff.spi.action.delete.BeforeDeleteAction;
import com.inspur.edp.bff.spi.action.delete.DefaultDeleteAction;
import com.inspur.edp.bff.spi.action.modify.AbstractModifyAction;
import com.inspur.edp.bff.spi.action.modify.AfterModifyAction;
import com.inspur.edp.bff.spi.action.modify.BeforeModifyAction;
import com.inspur.edp.bff.spi.action.modify.DefaultModifyAction;
import com.inspur.edp.bff.spi.action.multidelete.AbstractMultiDeleteAction;
import com.inspur.edp.bff.spi.action.multidelete.AfterMultiDeleteAction;
import com.inspur.edp.bff.spi.action.multidelete.BeforeMultiDeleteAction;
import com.inspur.edp.bff.spi.action.multidelete.DefaultMultiDeleteAction;
import com.inspur.edp.bff.spi.action.query.AbstractQueryAction;
import com.inspur.edp.bff.spi.action.query.AfterQueryAction;
import com.inspur.edp.bff.spi.action.query.BeforeQueryAction;
import com.inspur.edp.bff.spi.action.query.DefaultQueryAction;
import com.inspur.edp.bff.spi.action.retrieve.AbstractRetrieveAction;
import com.inspur.edp.bff.spi.action.retrieve.AfterRetrieveAction;
import com.inspur.edp.bff.spi.action.retrieve.BeforeRetrieveAction;
import com.inspur.edp.bff.spi.action.retrieve.DefaultRetrieveAction;
import com.inspur.edp.bff.spi.action.retrievedefault.AbstractRetrieveDefaultAction;
import com.inspur.edp.bff.spi.action.retrievedefault.AfterRetrieveDefaultAction;
import com.inspur.edp.bff.spi.action.retrievedefault.BeforeRetrieveDefaultAction;
import com.inspur.edp.bff.spi.action.retrievedefault.DefaultRetrieveDefaultAction;
import com.inspur.edp.bff.spi.action.save.AfterSaveAction;
import com.inspur.edp.bff.spi.action.save.BeforeSaveAction;
import com.inspur.edp.caf.generator.baseInfo.ParameterInfo;
import com.inspur.edp.caf.generator.baseInfo.TypeInfo;
import com.inspur.edp.caf.generator.method.ClassMethodGenerator;
import com.inspur.edp.formserver.viewmodel.GspViewModel;
import com.inspur.edp.formserver.viewmodel.action.MappedCdpAction;
import com.inspur.edp.formserver.viewmodel.action.ViewModelAction;
import com.inspur.edp.formserver.viewmodel.collection.VMActionCollection;
import com.inspur.edp.formserver.viewmodel.common.InternalExtendActionUtil;
import com.inspur.edp.lcm.metadata.api.entity.GspMetadata;
import org.eclipse.jdt.core.dom.*;

import java.util.ArrayList;

public class ActionConfigCtorGenerator extends ClassMethodGenerator {

    //C# TO JAVA CONVERTER TODO TASK: There is no preprocessor in Java:
    ///#region vo扩展操作
    public static final String ExAction_BeforeQueryTypes = "BeforeQueryTypes";
    public static final String ExAction_QueryTypes = "QueryTypes";
    public static final String ExAction_AfterQueryTypes = "AfterQueryTypes";
    public static final String ExAction_DataMapperTypes = "DataMapperTypes";
    public static final String ExAction_DataReversalMapperTypes = "DataReversalMapperTypes";
    public static final String ExAction_BeforeRetrieveTypes = "BeforeRetrieveTypes";
    public static final String ExAction_RetrieveTypes = "RetrieveTypes";
    public static final String ExAction_AfterRetrieveTypes = "AfterRetrieveTypes";
    public static final String ExAction_BeforeRetrieveDefaultTypes = "BeforeRetrieveDefaultTypes";
    public static final String ExAction_RetrieveDefaultTypes = "RetrieveDefaultTypes";
    public static final String ExAction_AfterRetrieveDefaultTypes = "AfterRetrieveDefaultTypes";
    public static final String ExAction_BeforeModifyTypes = "BeforeModifyTypes";
    public static final String ExAction_ModifyTypes = "ModifyTypes";
    public static final String ExAction_AfterModifyTypes = "AfterModifyTypes";
    public static final String ExAction_BeforeDeleteTypes = "BeforeDeleteTypes";
    public static final String ExAction_DeleteTypes = "DeleteTypes";
    public static final String ExAction_AfterDeleteTypes = "AfterDeleteTypes";
    public static final String ExAction_BeforeSaveTypes = "BeforeSaveTypes";
    public static final String ExAction_AfterSaveTypes = "AfterSaveTypes";
    public static final String ExAction_ChangeMapperTypes = "ChangeMapperTypes";
    public static final String ExAction_ChangeReversalMapperTypes = "ChangeReversalMapperTypes";
    public static final String ExAction_AfterMultiDeleteTypes="AfterMultiDeleteTypes";
    public static final String ExAction_BeforeMultiDeleteTypes="BeforeMultiDeleteTypes";
    public static final String ExAction_MultiDeleteTypes="MultiDeleteTypes";
    private VmCoreGenContext coreGenCtx;
    private GspViewModel vo;
    private String className;
    private java.util.HashMap<String, java.lang.Class> defaultActionType;
//C# TO JAVA CONVERTER TODO TASK: There is no preprocessor in Java:
    ///#endregion

    public ActionConfigCtorGenerator(VmCoreGenContext coreGenCtx, String className) {
        super();

        this.coreGenCtx = coreGenCtx;
        vo = coreGenCtx.getVmGenContext().getVm();
        this.className = className;
        defaultActionType = new java.util.HashMap<String, java.lang.Class>();
        defaultActionType.put(InternalExtendActionUtil.QueryActionId, DefaultQueryAction.class);
        defaultActionType
                .put(InternalExtendActionUtil.DataMappingActionId, DefaultDataMappingAction.class);
        defaultActionType
                .put(InternalExtendActionUtil.DataReversalMappingActionId, DefaultDataReversalAction.class);
        defaultActionType.put(InternalExtendActionUtil.RetrieveActionId, DefaultRetrieveAction.class);
        defaultActionType
                .put(InternalExtendActionUtil.CreateActionId, DefaultRetrieveDefaultAction.class);
        defaultActionType.put(InternalExtendActionUtil.ModifyActionId, DefaultModifyAction.class);
        defaultActionType.put(InternalExtendActionUtil.DeleteActionId, DefaultDeleteAction.class);
        defaultActionType.put(InternalExtendActionUtil.MultiDeleteActionId, DefaultMultiDeleteAction.class);
        defaultActionType
                .put(InternalExtendActionUtil.ChangesetMappingActionId, DefaultChangeMapAction.class);
        defaultActionType.put(InternalExtendActionUtil.ChangesetReversalMappingActionId,
                DefaultChangeReversalAction.class);

    }

    @Override
    protected boolean buildIsConstructor() {
        return true;
    }

    @Override
    protected String getMethodName() {
        return className;
    }

    @Override
    protected TypeInfo getReturnType() {
        return null;
    }

    //C# TO JAVA CONVERTER TODO TASK: Lambda expressions and anonymous methods are not converted by C# to Java Converter:
    @Override
    protected java.util.ArrayList<Modifier.ModifierKeyword> getAccessModifiers() {
        return new java.util.ArrayList<Modifier.ModifierKeyword>(
                java.util.Arrays.asList(new Modifier.ModifierKeyword[]{Modifier.ModifierKeyword.PUBLIC_KEYWORD}));
    }

    @Override
    protected ArrayList<ParameterInfo> getParameterCollection() {
        return null;
    }

    @Override
    protected Block buildMethodBody() {
        Block block = ast.newBlock();
        addNewTypes(block);
        addSetFields(block);
        return block;
    }

    private void addNewTypes(Block block) {
        ParameterizedType parameterizedType = ast.newParameterizedType(ast.newSimpleType(ast.newName(ArrayList.class.getTypeName())));
        parameterizedType.typeArguments().add(ast.newSimpleType(ast.newName(Class.class.getTypeName())));

        VariableDeclarationFragment variableDeclarationFragment = ast.newVariableDeclarationFragment();
        variableDeclarationFragment.setName(ast.newSimpleName("types"));
        variableDeclarationFragment.setInitializer(ast.newNullLiteral());

        VariableDeclarationStatement variableDeclarationStatement = ast.newVariableDeclarationStatement(variableDeclarationFragment);
        variableDeclarationStatement.setType(parameterizedType);
        block.statements().add(variableDeclarationStatement);

    }

    private void addSetFields(Block block) {
        buildInitStatement(ExAction_BeforeQueryTypes,
                vo.getDataExtendInfo().getBeforeQueryActions(), "", block);
        buildInitStatement(ExAction_QueryTypes,
                vo.getDataExtendInfo().getQueryActions(), InternalExtendActionUtil.QueryActionId, block);
        buildInitStatement(ExAction_AfterQueryTypes,
                vo.getDataExtendInfo().getAfterQueryActions(), "", block);
        buildInitStatement(ExAction_DataMapperTypes,
                vo.getDataExtendInfo().getDataMappingActions(), InternalExtendActionUtil.DataMappingActionId, block);
        buildInitStatement(
                ExAction_DataReversalMapperTypes, vo.getDataExtendInfo().getDataReversalMappingActions(),
                InternalExtendActionUtil.DataReversalMappingActionId, block);
        buildInitStatement(
                ExAction_BeforeRetrieveTypes, vo.getDataExtendInfo().getBeforeRetrieveActions(), "", block);
        buildInitStatement(ExAction_RetrieveTypes,
                vo.getDataExtendInfo().getRetrieveActions(), InternalExtendActionUtil.RetrieveActionId, block);
        buildInitStatement(
                ExAction_AfterRetrieveTypes, vo.getDataExtendInfo().getAfterRetrieveActions(), "", block);
        buildInitStatement(
                ExAction_BeforeRetrieveDefaultTypes, vo.getDataExtendInfo().getBeforeCreateActions(), null, block);
        buildInitStatement(ExAction_RetrieveDefaultTypes,
                vo.getDataExtendInfo().getCreateActions(), InternalExtendActionUtil.CreateActionId, block);
        buildInitStatement(
                ExAction_AfterRetrieveDefaultTypes, vo.getDataExtendInfo().getAfterCreateActions(), null, block);
        buildInitStatement(ExAction_BeforeModifyTypes,
                vo.getDataExtendInfo().getBeforeModifyActions(), null, block);
        buildInitStatement(ExAction_ModifyTypes,
                vo.getDataExtendInfo().getModifyActions(), InternalExtendActionUtil.ModifyActionId, block);
        buildInitStatement(ExAction_AfterModifyTypes,
                vo.getDataExtendInfo().getAfterModifyActions(), null, block);
        buildInitStatement(ExAction_BeforeDeleteTypes,
                vo.getDataExtendInfo().getBeforeDeleteActions(), null, block);
        buildInitStatement(ExAction_DeleteTypes,
                vo.getDataExtendInfo().getDeleteActions(), InternalExtendActionUtil.DeleteActionId, block);
        buildInitStatement(ExAction_AfterDeleteTypes,
                vo.getDataExtendInfo().getAfterDeleteActions(), null, block);
        buildInitStatement(ExAction_BeforeMultiDeleteTypes,
                vo.getDataExtendInfo().getBeforeMultiDeleteActions(),null,block);
        buildInitStatement(ExAction_MultiDeleteTypes,
        vo.getDataExtendInfo().getMultiDeleteActions(),InternalExtendActionUtil.MultiDeleteActionId,block);
        buildInitStatement(ExAction_AfterMultiDeleteTypes,
                vo.getDataExtendInfo().getAfterMultiDeleteActions(),null,block);
        buildInitStatement(ExAction_BeforeSaveTypes,
                vo.getDataExtendInfo().getBeforeSaveActions(), null, block);
        buildInitStatement(ExAction_AfterSaveTypes,
                vo.getDataExtendInfo().getAfterSaveActions(), null, block);
        buildInitStatement(ExAction_ChangeMapperTypes,
                vo.getDataExtendInfo().getChangesetMappingActions(),
                InternalExtendActionUtil.ChangesetMappingActionId, block);
        buildInitStatement(
                ExAction_ChangeReversalMapperTypes, vo.getDataExtendInfo().getChangesetReversalMappingActions(),
                InternalExtendActionUtil.ChangesetReversalMappingActionId, block);
    }

    private void buildInitStatement(String propName, VMActionCollection actions,
                                    String defaultActionId, Block block) {
        buildAssListStatement(block);
        if(propName.equals(ExAction_BeforeQueryTypes) && coreGenCtx.getDefaultQueryConditionType()!=null){
            buildAddType(block,coreGenCtx.getDefaultQueryConditionType().getFullName());
        }
//      if(defaultActionId!=null&&defaultActionId.equals("")==false)
//        buildAddType(block,defaultActionType.get(defaultActionId).getTypeName());
        for (ViewModelAction action : actions) {
            if (action.getID().equals(defaultActionId))
                buildAddType(block, defaultActionType.get(defaultActionId).getTypeName());
            else
                buildAddType(block, getActionTypeName(action));
        }
        buildAssignToField(block, propName);
    }

    private String getActionTypeName(ViewModelAction action) {
        MappedCdpAction mappedCdpAction = (MappedCdpAction) action;
        GspMetadata metadata = coreGenCtx.getVmGenContext().getMetadataPool().getMetadata(mappedCdpAction.getComponentPkgName(), mappedCdpAction.getComponentEntityId());
        if(metadata == null)
            throw new RuntimeException("未找到构件元数据["+mappedCdpAction.getCode()+"]，元数据id为" + mappedCdpAction.getComponentEntityId());
        VMComponent compMetadata = (VMComponent) metadata.getContent();
        VMMethod method = compMetadata.getVmMethod();
        return method.getClassName();
    }

    private void buildAssListStatement(Block block) {
        Assignment assignment = ast.newAssignment();
        assignment.setLeftHandSide(ast.newSimpleName("types"));
        assignment.setOperator(Assignment.Operator.ASSIGN);

        ClassInstanceCreation classInstanceCreation = ast.newClassInstanceCreation();
        ParameterizedType parameterizedType = ast.newParameterizedType(ast.newSimpleType(ast.newName(ArrayList.class.getTypeName())));
        parameterizedType.typeArguments().add(ast.newSimpleType(ast.newName(Class.class.getTypeName())));
        classInstanceCreation.setType(parameterizedType);
        assignment.setRightHandSide(classInstanceCreation);

        block.statements().add(ast.newExpressionStatement(assignment));
    }

    private void buildAddType(Block block, String typeName) {
        MethodInvocation methodInvocation = ast.newMethodInvocation();
        methodInvocation.setName(ast.newSimpleName("add"));
        methodInvocation.setExpression(ast.newSimpleName("types"));
        TypeLiteral typeLiteral = ast.newTypeLiteral();
        typeLiteral.setType(ast.newSimpleType(ast.newName(typeName)));
        methodInvocation.arguments().add(typeLiteral);

        block.statements().add(ast.newExpressionStatement(methodInvocation));
    }

    private void buildAssignToField(Block block, String propName) {
        Assignment assignment = ast.newAssignment();
        assignment.setLeftHandSide(ast.newSimpleName(propName + "Field"));
        assignment.setOperator(Assignment.Operator.ASSIGN);
        assignment.setRightHandSide(ast.newSimpleName("types"));
        block.statements().add(ast.newExpressionStatement(assignment));
    }


    private java.lang.Class getExtendActionBaseType(String propName) {
//C# TO JAVA CONVERTER NOTE: The following 'switch' operated on a string member and was converted to Java 'if-else' logic:
//		switch (propName)
//ORIGINAL LINE: case ExAction_BeforeQueryTypes:
        if (ExAction_BeforeQueryTypes.equals(propName)) {
            return BeforeQueryAction.class;
        }
//ORIGINAL LINE: case ExAction_QueryTypes:
        else if (ExAction_QueryTypes.equals(propName)) {
            return AbstractQueryAction.class;
        }
//ORIGINAL LINE: case ExAction_AfterQueryTypes:
        else if (ExAction_AfterQueryTypes.equals(propName)) {
            return AfterQueryAction.class;
        }
//ORIGINAL LINE: case ExAction_DataMapperTypes:
        else if (ExAction_DataMapperTypes.equals(propName)) {
            return DataMappingAction.class;
        }
//ORIGINAL LINE: case ExAction_DataReversalMapperTypes:
        else if (ExAction_DataReversalMapperTypes.equals(propName)) {
            return DataReversalMappingAction.class;
        }
//ORIGINAL LINE: case ExAction_BeforeRetrieveTypes:
        else if (ExAction_BeforeRetrieveTypes.equals(propName)) {
            return BeforeRetrieveAction.class;
        }
//ORIGINAL LINE: case ExAction_RetrieveTypes:
        else if (ExAction_RetrieveTypes.equals(propName)) {
            return AbstractRetrieveAction.class;
        }
//ORIGINAL LINE: case ExAction_AfterRetrieveTypes:
        else if (ExAction_AfterRetrieveTypes.equals(propName)) {
            return AfterRetrieveAction.class;
        }
//ORIGINAL LINE: case ExAction_BeforeRetrieveDefaultTypes:
        else if (ExAction_BeforeRetrieveDefaultTypes.equals(propName)) {
            return BeforeRetrieveDefaultAction.class;
        }
//ORIGINAL LINE: case ExAction_RetrieveDefaultTypes:
        else if (ExAction_RetrieveDefaultTypes.equals(propName)) {
            return AbstractRetrieveDefaultAction.class;
        }
//ORIGINAL LINE: case ExAction_AfterRetrieveDefaultTypes:
        else if (ExAction_AfterRetrieveDefaultTypes.equals(propName)) {
            return AfterRetrieveDefaultAction.class;
        }
//ORIGINAL LINE: case ExAction_BeforeModifyTypes:
        else if (ExAction_BeforeModifyTypes.equals(propName)) {
            return BeforeModifyAction.class;
        }
//ORIGINAL LINE: case ExAction_ModifyTypes:
        else if (ExAction_ModifyTypes.equals(propName)) {
            return AbstractModifyAction.class;
        }
//ORIGINAL LINE: case ExAction_AfterModifyTypes:
        else if (ExAction_AfterModifyTypes.equals(propName)) {
            return AfterModifyAction.class;
        }
//ORIGINAL LINE: case ExAction_BeforeDeleteTypes:
        else if (ExAction_BeforeDeleteTypes.equals(propName)) {
            return BeforeDeleteAction.class;
        }
//ORIGINAL LINE: case ExAction_DeleteTypes:
        else if (ExAction_DeleteTypes.equals(propName)) {
            return AbstractDeleteAction.class;
        }
//ORIGINAL LINE: case ExAction_AfterDeleteTypes:
        else if (ExAction_AfterDeleteTypes.equals(propName)) {
            return AfterDeleteAction.class;
        }
//ORIGINAL LINE: case ExAction_BeforeMultiDeleteTypes:
        else if (ExAction_BeforeMultiDeleteTypes.equals(propName)) {
            return BeforeMultiDeleteAction.class;
        }
//ORIGINAL LINE: case ExAction_MultiDeleteTypes:
        else if (ExAction_MultiDeleteTypes.equals(propName)) {
            return AbstractMultiDeleteAction.class;
        }
//ORIGINAL LINE: case ExAction_AfterMultiDeleteTypes:
        else if (ExAction_AfterMultiDeleteTypes.equals(propName)) {
            return AfterMultiDeleteAction.class;
        }
//ORIGINAL LINE: case ExAction_BeforeSaveTypes:
        else if (ExAction_BeforeSaveTypes.equals(propName)) {
            return BeforeSaveAction.class;
        }
//ORIGINAL LINE: case ExAction_AfterSaveTypes:
        else if (ExAction_AfterSaveTypes.equals(propName)) {
            return AfterSaveAction.class;
        }
//ORIGINAL LINE: case ExAction_ChangeMapperTypes:
        else if (ExAction_ChangeMapperTypes.equals(propName)) {
            return ChangeMappingAction.class;
        }
//ORIGINAL LINE: case ExAction_ChangeReversalMapperTypes:
        else if (ExAction_ChangeReversalMapperTypes.equals(propName)) {
            return ChangeReversalMappingAction.class;
        } else {
            throw new RuntimeException("未定义的vo扩展操作类型" + propName);
        }
    }

    private void checkExtendActionType(java.lang.Class type, String propName,
                                       ViewModelAction action) {
        String message = "vo元数据'" + vo.getCode() + "'中'{" + propName + "}'类型扩展操作'{" + action.getCode() + "}'";
        if (type == null) {
            throw new RuntimeException(message + "对应的构件类型'{type.Name}'未找到。");
        }
        java.lang.Class baseType = getExtendActionBaseType(propName);
//C# TO JAVA CONVERTER TODO TASK: There is no equivalent to implicit typing in Java:
        Boolean checkResult = baseType.isAssignableFrom(type);
        if (!checkResult) {
            throw new RuntimeException(message + "对应的构件类型基类应为{" + baseType.getTypeName() + "}，请修改。");
        }
    }
}
